/*
 * @Author: liuzelin
 * @Date: 2024-04-06 10:34:01
 * @LastEditors: liuzelin
 * @LastEditTime: 2024-05-01 14:07:07
 * @Description: file content
 */
#pragma once

#include <stdint.h>

#include <climits>  // 为CHAR_BIT
#include <sstream>
#include <string>
#include <vector>

namespace PandaUtils {
class SACKGenerator {
 public:
  SACKGenerator() {}

  const std::string& ToString() {
    if (str.empty()) {
      std::stringstream ss;
      BuildBaseSeqString(ss);
      BuildBitMapString(ss);
      str = ss.str();
    }
    return str;
  }

  bool receivePacket(uint16_t seqNum) {
    uint16_t diff = seqNum - minSeqNum;
    if (diff > 0x7fff) {
      return false;
    }
    str.clear();
    UpdateBitMap(seqNum);
    return true;
  }

  const std::vector<uint8_t>& getBitmap() const { return bitmap; }
  uint16_t getMinSeqNum() const { return minSeqNum; }

 private:
  std::vector<uint8_t> bitmap;
  uint16_t minSeqNum = 0;
  std::string str;

  void BuildBaseSeqString(std::stringstream& ss) {
    ss << "BaseSeq:" << minSeqNum
       << (bitmap.empty() ? " BitMap:Empty" : " BitMap:");
  }

  void BuildBitMapString(std::stringstream& ss) {
    uint16_t seq = minSeqNum;
    for (auto& bit : bitmap) {
      seq += CHAR_BIT;
      for (size_t i = 0; i < CHAR_BIT; i++) {
        ss << ((bit & (1 << (CHAR_BIT - 1 - i))) ? "1" : "0");
      }
      ss << ":" << seq << " ";
    }
  }

  void UpdateBitMap(uint16_t seqNum) {
    if (seqNum == minSeqNum) {
      AdvanceMinSeqNum();
    } else {
      SetBit(seqNum);
    }
  }

  void AdvanceMinSeqNum() {
    uint16_t shiftCount = 1;
    while (isBitSet(minSeqNum + shiftCount)) {
      shiftCount++;
    }
    if (shiftCount > 0) {
      ShiftLeft(shiftCount);
      minSeqNum += shiftCount;
    }
  }

  void SetBit(uint16_t seqNum) {
    if (seqNum == minSeqNum) return;
    uint16_t diff = seqNum - minSeqNum;
    size_t index = diff / CHAR_BIT;
    size_t bitPos = diff % CHAR_BIT;
    if ((bitPos == 0 && index > bitmap.size()) ||
        (bitPos && index >= bitmap.size())) {
      bitmap.resize(index + 1, 0);
    }
    if (bitPos)
      bitmap[index] |= (1 << (CHAR_BIT - bitPos));
    else
      bitmap[index - 1] |= 1;
  }

  bool isBitSet(uint16_t seqNum) const {
    uint16_t diff = seqNum - minSeqNum;
    size_t index = (diff - 1) / CHAR_BIT;
    if (index >= bitmap.size()) {
      return false;
    }
    int bitPos = ((diff - 1) % CHAR_BIT) + 1;
    return (bitmap[index] & (0x1 << (CHAR_BIT - bitPos)));
  }

  void ShiftLeft(uint16_t n) {
    if (bitmap.empty()) {
      return;
    }
    if (n >= bitmap.size() * CHAR_BIT) {
      bitmap.clear();
      return;
    }
    int byteShift = n / CHAR_BIT;
    int bitShift = n % CHAR_BIT;
    int bitOverflow = CHAR_BIT - bitShift;
    for (size_t i = 0; i < bitmap.size() - byteShift - 1; ++i) {
      bitmap[i] = (bitmap[i + byteShift] << bitShift) |
                  (bitmap[i + byteShift + 1] >> bitOverflow);
    }
    bitmap[bitmap.size() - byteShift - 1] = bitmap.back() << bitShift;
    if (bitmap[bitmap.size() - byteShift - 1])
      bitmap.erase(bitmap.end() - byteShift, bitmap.end());
    else
      bitmap.erase(bitmap.end() - byteShift - 1, bitmap.end());
  }
};
}  // namespace PandaUtils
